/**
 * manage all terminals in outline grammars
 * manage all regex of all terminals
 * return an enum object: terminals
 * eg: in formal language - regex language: A = aB, the "a" is Terminal
 * huizi 2024
 */
import {CONSTANTS} from '../common/consts.js';

/**
 * build termnal object
 * huizi 2024
 */
function terminal(name, regex, isKey=false){
    const text = regex.replace("\\","");
    return {
        regex: ()=>{
            if(isKey===true){
                return `(?<${name}>(?<!\\w)${regex}(?!\\w))`;
            }else{
                return `(?<${name}>${regex})`
            }
        },
        text: ()=>text,
        name: ()=>name,
        isTerminal:()=>true
    };
}


/**
 * all terminals in outline
 * huizi 2024
 */
const Terminals = ((...all)=>{
    /**
     * closure all teminals for regex build
     */
    const terminals = {};

    /**
     * final result for terminal enums
     */
    const result = new Proxy({}, {
        get: function (target, key, receiver) {
            let value = target[key];
            if(value===undefined){
                return terminals[key];
            }else{
                return value;
            }
        }
    });

    /**
     * get the terminal from name
     */
    result.valueOf = name=>terminals[name.toUpperCase()];
    
    /**
     * build regex based on all terminal regex
     * this regex is for tokenize a line of outline code
     */
    result.regex = ()=>{
        let result = [];
        for(let key in terminals){
            let value = terminals[key];
            result.push(value.regex());
            result.push(CONSTANTS.PIPE);
        }
        result.pop();
        return result.join('');
    }

    all.forEach(t=>{
        const [name,regex,isKey] = t;
        terminals[name] = terminal(name,regex,isKey==undefined?false:isKey);
    })

    return Object.freeze(result);
})(
     ["END","\\$"],
     ["PLUS_PLUS","\\+\\+"],
     ["MINUS_ARROW", "->"],
     ["MINUS_MINUS", "--"],
     ["BANG_EQUAL", "!="],
     ["EQUAL_EQUAL", "=="],
     ["GREATER_EQUAL", ">="],
     ["LESS_EQUAL", "<="],
     ["EQUAL_GREATER", "=>"],
     ["GREATER_GREATER", ">>"],
     ["TYPE_OF", "<:"],["EXTEND_TO", ":>"],
     ["EXACT_TYPE_OF", "=:"],
     ["AND_AND", "&&"],
     ["OR_OR", "\\|\\|"],
     ["PLUS_EQUAL", "\\+="],
     ["MINUS_EQUAL", "-="],
     ["STAR_EQUAL", "\\*="],
     ["SLASH_EQUAL", "\\/="],
     ["COMMENT", "#.*"],
     ["WAVE", "~"],
     ["STRING_TYPE", "_string_"],
     ["NUMBER_TYPE", "_number_"],
     ["BOOL_TYPE", "_bool_"],
     ["OBJECT_TYPE", "_object_"],
     ["FUNCTION_TYPE", "_function_"],
     ["ARRAY_TYPE", "_array_"],
     ["MAP_TYPE", "_map_"],
     ["ENTITY_BODY_BEGIN","\\{(\\s|\\n|\\r)*\\."],
     ["LEFT_PAREN", "\\("],
     ["RIGHT_PAREN", "\\)"],
     ["LEFT_BRACE", "\\{"],
     ["RIGHT_BRACE", "\\}"],
     ["LEFT_BRACKET", "\\["],
     ["RIGHT_BRACKET", "\\]"],
     ["COMMA", "\\,"],
     ["DOT_DOT", "\\.\\."],
     ["DOT", "\\."],
     ["MATCH_ELSE", "\\|\\s*_\\s*\\=\\>"],
     ["MINUS", "-"],
     ["BANG", "!"],
     ["EQUAL", "="],
     ["GREATER", ">"],
     ["LESS", "<"],
     ["PLUS", "\\+"],
     ["SEMICOLON", "\\;"],
     ["SLASH", "\\/"],
     ["STAR", "\\*"],
     ["AND", "&"],
     ["OR", "\\|"],
     ["MOD", "\\%"],
     ["POWER", "\\^"],
     ["QUESTION", "\\?"],
     ["COLON", "\\:"],
     ["NUMBER","(?:\\b|(?<=[\\=\\<\\>])\\s*-\\s*)\\d+(?:\\.\\d+)?(?![\\.])\\b"],
     ["STRING","\\\"[^\"]*\\\""],
     ["BACKTICK","`"],
     ["EOL", "$"],
     ["EPSILON", "ε"],
     ["UNIT", "(ε)"],
     ["ENTER","\\S* \\n"],
     ["EACH", "each",  true],
     ["LET", "let",  true],
     ["VAR", "var",  true],
     ["IF", "if",  true],
     ["ELSE", "else",  true],
     ["WHILE", "while",  true],
     ["DO", "do",  true],
     ["FOR", "for",  true],
     ["IN", "in",  true],
     ["MATCH", "match",  true],
     ["BREAK", "break",  true],
     ["CONTINUE", "continue",  true],
     ["RETURN", "return",  true],
     ["IMPORT", "import",  true],
     ["EXPORT", "export", true],
     ["NAME_SPACE", "namespace",  true],
     ["TRUE", "true",  true],
     ["FALSE", "false",  true],
     ["FUNC", "func",  true],
     ["ENTITY", "entity",  true],
     ["TUPLE", "_tuple",  true],
     ["FROM", "from",  true],
     ["AS", "as",  true],
     ["ID","([a-zA-Z_]\\w*)"],
     ["UNKNOWN", "\\w+|\\S"]
);

export {Terminals};